/***************************
SEGX2 - Smooth Expander Gate
Copyright (C) 2015 Stige T.
***************************/

desc:SEGX2 - Smooth Dual Band Expander Gate [Build 151011]

slider1:0<0,10,0.1>Attack
slider2:20<20,1000,1>Release Lo
slider3:20<20,1000,1>Release Hi
slider4:-45<-90,0,1>Threshold Lo
slider5:-45<-90,0,1>Threshold Hi
slider6:500<50,10000,10>Crossover
slider7:1<0.5,10,0.1>Ratio [Expander <> Gate]
slider8:0<0,3,1{Output,Detector,Lo-band,Hi-band}>Monitor
slider9:0<0,1,1{Off (0spl),On (64spl)}>Pre-Gate

@init

t20 = exp(-1/(srate*0.02));
t40 = exp(-1/(srate*0.04));

function delay64spl(input) (
  this.x0 = input;
  this.x65=this.x64; this.x64=this.x63; this.x63=this.x62; this.x62=this.x61; this.x61=this.x60; this.x60=this.x59; this.x59=this.x58;
  this.x58=this.x57; this.x57=this.x56; this.x56=this.x55; this.x55=this.x54; this.x54=this.x53; this.x53=this.x52; this.x52=this.x51;
  this.x51=this.x50; this.x50=this.x49; this.x49=this.x48; this.x48=this.x47; this.x47=this.x46; this.x46=this.x45; this.x45=this.x44;  
  this.x44=this.x43; this.x43=this.x42; this.x42=this.x41; this.x41=this.x40; this.x40=this.x39; this.x39=this.x38; this.x38=this.x37;
  this.x37=this.x36; this.x36=this.x35; this.x35=this.x34; this.x34=this.x33; this.x33=this.x32; this.x32=this.x31; this.x31=this.x30;
  this.x30=this.x29; this.x29=this.x28; this.x28=this.x27; this.x27=this.x26; this.x26=this.x25; this.x25=this.x24; this.x24=this.x23;
  this.x23=this.x22; this.x22=this.x21; this.x21=this.x20; this.x20=this.x19; this.x19=this.x18; this.x18=this.x17; this.x17=this.x16;
  this.x16=this.x15; this.x15=this.x14; this.x14=this.x13; this.x13=this.x12; this.x12=this.x11; this.x11=this.x10; this.x10=this.x9;
  this.x9=this.x8; this.x8=this.x7; this.x7=this.x6; this.x6=this.x5; this.x5=this.x4; this.x4=this.x3; this.x3=this.x2; this.x2=this.x1; this.x1=this.x0;
  this.x65;
);

function HFLF_init(freq)
instance(n0,weight)
(
  n0 = 0;
  weight = 1-exp(-2*$pi*freq/srate);
);

function HFcut(input)
instance(out,n0,weight)
(  
  out = (n0+=((input-n0)*weight));
);

function LFcut(input)
instance(out,n0,weight)
(
  out = input - (n0+=((input-n0)*weight));
);

function follower(input,att,rel)
instance (env,tmp) (
  tmp = input >= tmp ? input : input + t40 * (tmp-input);
  (tmp > env) ? (
      env = att * (env - tmp) + tmp;
  ) : (
      env = rel * (env - tmp) + tmp;
  );
);

function expander_gate(input,threshold,attack,release,ratio,mon)
instance(env,e1,e2,e3,output,mon)
(
  env = min(abs(input),threshold);
  env = env / threshold;
  env = env^ratio;
  env = e1.follower(env,attack,release);
  
  lat ? (  
    input = this.delay64spl(input);
  );  
  
  mon != 1 ? (
    output = input * env;
  );
  mon == 1 ? (
    output = (input * env) - input;
  );
  output;
);

@slider

attack = exp(-1/(srate*slider1/1000));
release = exp(-1/(srate*slider2/1000));
release2 = exp(-1/(srate*slider3/1000));
threshold = 10^(slider4/20);
threshold2 = 10^(slider5/20);
crossover = slider6;
ratio = slider7;
mon = slider8;
lat = slider9;
lb = hb = 1;
mon == 2 ? hb = 0;
mon == 3 ? lb = 0;

f0.HFLF_init(crossover);
f1.HFLF_init(crossover);
f2.HFLF_init(crossover);
f3.HFLF_init(crossover);

lat ? (
  pdc_delay = 64;
  pdc_bot_ch = 0; pdc_top_ch = 2;
);

@sample

spl0 != spl1 ? (
  spl0 = (L_lo.expander_gate(f0.HFcut(spl0),threshold,attack,release,ratio,mon)*lb) + (L_hi.expander_gate(f1.LFcut(spl0),threshold2,attack,release2,ratio,mon)*hb);
  spl1 = (R_lo.expander_gate(f2.HFcut(spl1),threshold,attack,release,ratio,mon)*lb) + (R_hi.expander_gate(f3.LFcut(spl1),threshold2,attack,release2,ratio,mon)*hb);
  renv_lo = max(L_lo.env,R_lo.env);
  renv_hi = max(L_hi.env,R_hi.env);
) : (
  spl0 = spl1 = (L_lo.expander_gate(f0.HFcut(spl0),threshold,attack,release,ratio,mon)*lb) + (L_hi.expander_gate(f1.LFcut(spl0),threshold2,attack,release2,ratio,mon)*hb);
  renv_lo = L_lo.env;
  renv_hi = L_hi.env;
);

@gfx

gfx_setfont(1,"Arial",14);

function draw_meter(redux,y_pos,drawlabels)
instance(redux,col1,col2,x_pos)
(

  x_pos = floor(gfx_w/2)-100;
  gfx_r = 1; gfx_g = 1; gfx_b = 1; gfx_a = 1;
  gfx_x = x_pos; gfx_y = y_pos;
  gfx_rectto(200+x_pos,10+y_pos);

  drawlabels ? (
    gfx_x = 199+x_pos; gfx_y = 10+y_pos;
    gfx_lineto(199+x_pos,20+y_pos,0);
    gfx_drawchar($'O');
    gfx_x = 112+x_pos; gfx_y = 10+y_pos;
    gfx_lineto(112+x_pos,20+y_pos,0);
    gfx_drawnumber(10,0);
    gfx_x = 64+x_pos; gfx_y = 10+y_pos;
    gfx_lineto(64+x_pos,20+y_pos,0);
    gfx_drawnumber(20,0);
    gfx_x = 20+x_pos; gfx_y = 10+y_pos;
    gfx_lineto(20+x_pos,20+y_pos,0);
    gfx_drawnumber(40,0);
    gfx_x = x_pos; gfx_y = 10+y_pos;
    gfx_lineto(x_pos,20+y_pos,0);
    gfx_drawchar($'C');
  );

  gfx_r = 0; gfx_g = 0.9; gfx_b = 0; gfx_a = 1;
  gfx_x = 199+x_pos;
  gfx_y = y_pos+1;
  redux = floor(max(sqrt( redux )*200,1));
  gfx_rectto(redux+x_pos,9+y_pos);

  gfx_r = 1; gfx_g = 1; gfx_b = 1; gfx_a = 1;
  gfx_x = x_pos-20; gfx_y = y_pos;
  gfx_rectto(x_pos-10,10+y_pos);
  gfx_x = 210+x_pos; gfx_y = y_pos;
  gfx_rectto(220+x_pos,10+y_pos);

  redux == 1 ? (
    col1 = 1;
  );
  redux >= 199 ? (
    col2 = 1;
  );

  gfx_r = 1 * col1; gfx_g = 0; gfx_b = 0;
  gfx_x = x_pos-19; gfx_y = y_pos+1;
  gfx_rectto(x_pos-11,9+y_pos);

  gfx_r = 1 * col2; gfx_g = 0; gfx_b = 0;
  gfx_x = 211+x_pos; gfx_y = y_pos+1;
  gfx_rectto(219+x_pos,9+y_pos);
  
  col1 = max(col1-0.05,0);
  col2 = max(col2-0.05,0);

);

m0.draw_meter(renv_lo,10,0);
m1.draw_meter(renv_hi,21,1);

